package com.leyou.search.service.impl;

import com.leyou.common.pojo.PageResult;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.SpecParam;
import com.leyou.search.client.BrandClient;
import com.leyou.search.client.CategoryClient;
import com.leyou.search.client.SpecClient;
import com.leyou.search.pojo.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.service.SearchService;
import com.leyou.search.utils.SearchRequest;
import com.leyou.search.utils.SearchResult;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private SpecClient specClient;

    @Override
    public SearchResult page(SearchRequest searchRequest) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //获取查询的key
        String key = searchRequest.getKey();
        if (StringUtils.isBlank(key)){
            return null;
        }
        QueryBuilder query = buildBasicQueryWithFilter(searchRequest);
        queryBuilder.withQuery(query);
        //创建自定义查询
        Integer page = searchRequest.getPage()-1;
        Integer size = searchRequest.getSize();


        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"id","skus","subTitle"}, null));
        //
        // queryBuilder.withQuery(QueryBuilders.matchQuery("all",key));
        //queryBuilder.withQuery(QueryBuilders.matchQuery("all", key).operator(Operator.AND));
        queryBuilder.withPageable(PageRequest.of(page,size));

        List<Category> categories = new ArrayList<>();

        List<Brand> brands = new ArrayList<>();
        // 1.3、聚合
        String categoryAggName = "category"; // 商品分类聚合名称
        String brandAggName = "brand"; // 品牌聚合名称
        queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));
        queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));
        //聚合查询
        AggregatedPage<Goods> goodsPage = (AggregatedPage<Goods>) goodsRepository.search(queryBuilder.build());
        //获取分类信息的聚合
        LongTerms categoriesTerm = (LongTerms) goodsPage.getAggregation(categoryAggName);
        List<Long> cids = new ArrayList<>();
        List<LongTerms.Bucket> buckets = categoriesTerm.getBuckets();
        //获取所得分类id信息集合
        buckets.forEach(bucket -> cids.add(bucket.getKeyAsNumber().longValue()));

        List<String> names = this.categoryClient.queryNameByIds(cids);
        for (int i = 0; i <cids.size() ; i++) {
            Category category = new Category();
            category.setId(cids.get(i));
            category.setName(names.get(i));
            categories.add(category);
        }

        //获取品牌信息的聚合
        LongTerms brandTerms = (LongTerms) goodsPage.getAggregation(brandAggName);
        List<Long> brandIds = new ArrayList<>();
        List<LongTerms.Bucket> buckets1 = brandTerms.getBuckets();
        //获取所有品牌id的集合
        buckets1.forEach(bucket -> brandIds.add(bucket.getKeyAsNumber().longValue()));

        //把品牌id集合和分类id集合转换成对象集合
        brandIds.forEach(id->{
            Brand brand = this.brandClient.queryBrandById(id);
            brands.add(brand);
        });

        long totalElements = goodsPage.getTotalElements();

        //int totalPages = goodsPage.getTotalPages();
        long totalPage = (totalElements + size - 1) / size;
        PageResult<Goods> result = new PageResult<>();

        List<Map<String, Object>> specs = null;
        //只有当分类唯一时,才展示规格参数
        if (categories.size()==1){
            specs =  getSpecs(categories.get(0).getId(),query);
        }

        return new SearchResult(totalElements,totalPage,goodsPage.getContent(),categories,brands,specs);
    }

    private List<Map<String, Object>> getSpecs(Long id,QueryBuilder query) {
        List<Map<String,Object>> speclist = new ArrayList<>();
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(query);
        //查询所有的规格参数
        List<SpecParam> params = this.specClient.querySpecParam(null, id, true);
        //添加聚合
        params.forEach(specParam -> {
            queryBuilder.addAggregation(AggregationBuilders.terms(specParam.getName()).field("specs."+specParam.getName()+".keyword"));
        });
        AggregatedPage<Goods> page = (AggregatedPage<Goods>) goodsRepository.search(queryBuilder.build());

        //解析聚合
        params.forEach(specParam ->{
            String name = specParam.getName();
            StringTerms stringTerms = (StringTerms) page.getAggregation(name);
            List<String> values = new ArrayList<>();
            List<StringTerms.Bucket> buckets = stringTerms.getBuckets();

            buckets.forEach(bucket -> values.add(bucket.getKeyAsString()));

                Map<String,Object> specmap = new HashMap<>();
                specmap.put("k",name);//k=====cpu的品牌
                specmap.put("options",values);//options===[],[],[],cpu品牌的值
                speclist.add(specmap);

        } );
        return speclist;
    }

    // 构建基本查询条件
    private QueryBuilder buildBasicQueryWithFilter(SearchRequest request) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 基本查询条件
        queryBuilder.must(QueryBuilders.matchQuery("all", request.getKey()).operator(Operator.AND));
        // 过滤条件构建器
        BoolQueryBuilder filterQueryBuilder = QueryBuilders.boolQuery();
        // 整理过滤条件
        Map<String, String> filter = request.getFilter();
        for (Map.Entry<String, String> entry : filter.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            // 商品分类和品牌可以直接查询不需要拼接
            if (key != "cids" && key != "brandId") {
                key = "specs." + key + ".keyword";
            }
            // 字符串类型，进行term查询
            filterQueryBuilder.must(QueryBuilders.termQuery(key, value));
        }
        // 添加过滤条件
        queryBuilder.filter(filterQueryBuilder);
        return queryBuilder;
    }
}
